﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SIEGate.Core;
using SIEGate.Core.Configurator;
using SIEGate.Core.MessageBusses;

namespace StressTests1
{

    class Runtime
    {
        private const int nSenders = 1;
        private const int nGatherers = 10;
        private uint count = 0;
        private List<IConfigInfo> allAdapters = new List<IConfigInfo>();
        private ISet<Guid> sourceIDs;
        private ISet<Guid> idMaps;
        private ISet<Guid> gatherResultIDs;
        private ConfigGraph m_graph;
        public List<IDataProcessor> ThreadThings;
        public SampleCondenserNetworkCommunicator OutputGuy;
        public IMessageBus bus;

        private ISet<Guid> makeSenders()
        {
            HashSet<Guid> res = new HashSet<Guid>();
            for (int i = 0; i < nSenders; i++)
            {
                Guid OutgoingSID = Guid.NewGuid();
                IConfigInfo info = new SampleArrayProducingDataProcessor.NetworkCommunicatorInfo();
                info.RuntimeType = typeof(SampleArrayProducingDataProcessor);
                info.ID = getCount();
                info.Name = "ArrayProducer" + info.ID.ToString();

                info.Update(new Dictionary<string, string>() { { "outgoingStreamIDs", OutgoingSID.ToString() } });
                info.ExtractConfiguration(new DataSet());

                allAdapters.Add(info);
                res.Add(OutgoingSID);
            }
            return res;

        }

        private uint getCount()
        {
            count++;
            return count;
        }

        private ISet<Guid> makeGatherers()
        {
            ISet<Guid> res = new HashSet<Guid>();
            for (int i = 0; i < nGatherers; i++)
            {
                IAdapterInfo info = new GatherSamplesAdapter.AdapterInfo();
                info.RuntimeType = typeof(GatherSamplesAdapter);
                info.ID = getCount();
                info.Name = "Gatherer" + info.ID.ToString();

                Guid g1 = Guid.NewGuid();

                info.Update(new Dictionary<string, string>()
                {
                    {"incomingStreamIDs", string.Join(";", idMaps.Select((g) => g.ToString()).ToArray())},
                    {"outgoingStreamIDs", g1.ToString()}
                });
                info.ExtractConfiguration(new DataSet());
                allAdapters.Add(info);
                res.Add(g1);
                IAdapter foo = new GatherSamplesAdapter(info);
            }
            return res;
        }

        private ISet<Guid> makeMappers()
        {
            ISet<Guid> res = new HashSet<Guid>();
            foreach (Guid sourceID in sourceIDs)
            {
                IAdapterInfo info = new MapSamplesAdapter.AdapterInfo();
                info.RuntimeType = typeof(MapSamplesAdapter);
                info.ID = getCount();
                info.Name = "Mapper" + info.ID.ToString();

                Guid g1 = Guid.NewGuid();
                Guid g2 = Guid.NewGuid();

                info.Update(new Dictionary<string, string>() { 
                    { "incomingStreamIDs", sourceID.ToString() }, 
                    {"outgoingStreamIDs", string.Join(";", new string[] {g1.ToString(), g2.ToString()})}
                });
                info.ExtractConfiguration(new DataSet());
                allAdapters.Add(info);
                res.Add(g1);
                res.Add(g2);

                IAdapter foo = new MapSamplesAdapter(info);
            }
            return res;
        }

        public void Setup()
        {
            sourceIDs = makeSenders();
            idMaps = makeMappers();
            gatherResultIDs = makeGatherers();
            IConfigInfo info = new SampleCondenserNetworkCommunicator.NetworkCommunicatorInfo();
            info.RuntimeType = typeof(SampleCondenserNetworkCommunicator);
            info.ID = getCount();
            info.Name = "Condenser" + info.ID.ToString();

            info.Update(new Dictionary<string, string>()
            {
                {"incomingStreamIDs", string.Join(";", gatherResultIDs.Select((g) => g.ToString()))}
            });
            info.ExtractConfiguration(new DataSet());
            allAdapters.Add(info);
            m_graph.Build(allAdapters);
            m_graph.Collapse();

            foreach (IDataProcessorInfo dpInfo in m_graph.Nodes)
            {
                IDataProcessor dProcessor = (IDataProcessor)Activator.CreateInstance(dpInfo.RuntimeType, bus.GetProxy(dpInfo.Name), dpInfo);
                if (dProcessor is SampleCondenserNetworkCommunicator)
                {
                    OutputGuy = (dProcessor as SampleCondenserNetworkCommunicator);
                }
                ThreadThings.Add(dProcessor);
            }
        }

        public Runtime()
        {
            m_graph = new ConfigGraph();
            ThreadThings = new List<IDataProcessor>();
        }

    }
    class Program
    {
        private static int outcount = 0;
        private static Runtime myruntime;
        static void ShowStats(object source, EventArgs args)
        {
            SampleCondenserNetworkCommunicator ds = myruntime.OutputGuy;
            if (outcount % 10 == 0)
            {
                outcount = 0;
                Console.WriteLine("Histogram:");
                foreach (Guid k in ds.histogram.Keys.ToArray())
                {
                    Console.WriteLine("{0} => {1}", k, ds.histogram[k]);
                }
                Console.WriteLine("Measuremnts:                         Groups:");
                Console.WriteLine("Mcount | avglat | maxlat | minlat || Gcount | avglat | maxlat | minlat | avgspr | maxspr| minspr");
            }
            Console.WriteLine("{0,-6} | {1,-6} | {2,-6} | {3,-6} || {4,-6} | {5,-6} | {6,-6} | {7,-6} | {8,-6} | {9,-6} | {10,-6}",
                    ds.MeasurementCount, ds.AvgMeasurementLatency, ds.MaxMeasuremntLatency, ds.MinMeasurementLatency,
                    ds.CompleteGroups, ds.GroupLatency, ds.GroupLatencyMax, ds.GroupLatencyMin, ds.GroupRecvSpread, ds.MaxGroupRecvSpread, ds.MinGroupRecvSpread);
            outcount++;
        }

        static void Main(string[] args)
        {
            System.Timers.Timer output = new System.Timers.Timer(1000);

            myruntime = new Runtime();
            IMessageBus mbus = new ChannelMessageBus();
            myruntime.bus = mbus;
            myruntime.Setup();

            List<Thread> workers = new List<Thread>();
            foreach (IDataProcessor dp in myruntime.ThreadThings)
            {
                IDataProcessor capturedp = dp;
                dp.Register();
                Thread doitThread = new Thread(capturedp.Start);

                workers.Add(doitThread);
                doitThread.IsBackground = true;
                doitThread.Start();
            }

            output.Elapsed += ShowStats;
            output.Enabled = true;
            Console.ReadKey();
            foreach (IDataProcessor dp in myruntime.ThreadThings)
            {
                dp.Stop();
            }
            foreach (Thread t in workers)
            {
                t.Join();
            }
            Console.WriteLine("exiting");
        }


    }
}
